From: Ross Philipson Date: Fri, 15 Feb 2013 13:32:16 +0000 (+0000) Subject: libxl: HVM firmware passthrough support X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~7272 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=dcd468855afed1fd205278beb60a4e3df21b3289;p=xen.git libxl: HVM firmware passthrough support This patch introduces support for two new parameters in libxl: smbios_firmware= acpi_firmware= The changes are primarily in the domain building code where the firmware files are read and passed to libxc for loading into the new guest. After the domain building call to libxc, the addresses for the loaded blobs are returned and written to xenstore. LIBXL_HAVE_FIRMWARE_PASSTHROUGH is defined in libxl.h to allow users to determine if the feature is present. This patch also updates the xl.cfg man page with descriptions of the two new parameters for firmware passthrough. Signed-off-by: Ross Philipson Acked-by: Ian Campbell Committed-by: Ian Campbell --- diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index caba1628f5..48e05c4a7c 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -829,6 +829,25 @@ libxl: 'host,tm=0,sse3=0' More info about the CPUID instruction can be found in the processor manuals, and in Wikipedia: L +=item B + +Specify a path to a file that contains extra ACPI firmware tables to pass in to +a guest. The file can contain several tables in their binary AML form +concatenated together. Each table self describes its length so no additional +information is needed. These tables will be added to the ACPI table set in the +guest. Note that existing tables cannot be overridden by this feature. For +example this cannot be used to override tables like DSDT, FADT, etc. + +=item B + +Specify a path to a file that contains extra SMBIOS firmware structures to pass +in to a guest. The file can contain a set DMTF predefined structures which will +override the internal defaults. Not all predefined structures can be overridden, +only the following types: 0, 1, 2, 3, 11, 22, 39. The file can also contain any +number of vendor defined SMBIOS structures (type 128 - 255). Since SMBIOS +structures do not present their overall size, each entry in the file must be +preceded by a 32b integer indicating the size of the next structure. + =back =head3 Guest Virtual Time Controls diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 72e5efb6d1..030aa86d52 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -67,6 +67,13 @@ * the same $(XEN_VERSION) (e.g. throughout a major release). */ +/* + * LIBXL_HAVE_FIRMWARE_PASSTHROUGH indicates the feature for + * passing in SMBIOS and ACPI firmware to HVM guests is present + * in the library. + */ +#define LIBXL_HAVE_FIRMWARE_PASSTHROUGH 1 + /* * libxl ABI compatibility * diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 33ae5583d8..8fe4fc4d06 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -21,6 +21,7 @@ #include #include +#include libxl_domain_type libxl__domain_type(libxl__gc *gc, uint32_t domid) { @@ -510,11 +511,61 @@ static int hvm_build_set_params(xc_interface *handle, uint32_t domid, return 0; } -static const char *libxl__domain_firmware(libxl__gc *gc, - libxl_domain_build_info *info) +static int hvm_build_set_xs_values(libxl__gc *gc, + uint32_t domid, + struct xc_hvm_build_args *args) +{ + char *path = NULL; + int ret = 0; + + if (args->smbios_module.guest_addr_out) { + path = GCSPRINTF("/local/domain/%d/"HVM_XS_SMBIOS_PT_ADDRESS, domid); + + ret = libxl__xs_write(gc, XBT_NULL, path, "0x%"PRIx64, + args->smbios_module.guest_addr_out); + if (ret) + goto err; + + path = GCSPRINTF("/local/domain/%d/"HVM_XS_SMBIOS_PT_LENGTH, domid); + + ret = libxl__xs_write(gc, XBT_NULL, path, "0x%x", + args->smbios_module.length); + if (ret) + goto err; + } + + if (args->acpi_module.guest_addr_out) { + path = GCSPRINTF("/local/domain/%d/"HVM_XS_ACPI_PT_ADDRESS, domid); + + ret = libxl__xs_write(gc, XBT_NULL, path, "0x%"PRIx64, + args->acpi_module.guest_addr_out); + if (ret) + goto err; + + path = GCSPRINTF("/local/domain/%d/"HVM_XS_ACPI_PT_LENGTH, domid); + + ret = libxl__xs_write(gc, XBT_NULL, path, "0x%x", + args->acpi_module.length); + if (ret) + goto err; + } + + return 0; + +err: + LOG(ERROR, "failed to write firmware xenstore value, err: %d", ret); + return ret; +} + +static int libxl__domain_firmware(libxl__gc *gc, + libxl_domain_build_info *info, + struct xc_hvm_build_args *args) { libxl_ctx *ctx = libxl__gc_owner(gc); const char *firmware; + int e, rc = ERROR_FAIL; + int datalen = 0; + void *data; if (info->u.hvm.firmware) firmware = info->u.hvm.firmware; @@ -528,13 +579,52 @@ static const char *libxl__domain_firmware(libxl__gc *gc, firmware = "hvmloader"; break; default: - LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "invalid device model version %d", - info->device_model_version); - return NULL; + LOG(ERROR, "invalid device model version %d", + info->device_model_version); + return ERROR_FAIL; break; } } - return libxl__abs_path(gc, firmware, libxl__xenfirmwaredir_path()); + args->image_file_name = libxl__abs_path(gc, firmware, + libxl__xenfirmwaredir_path()); + + if (info->u.hvm.smbios_firmware) { + data = NULL; + e = libxl_read_file_contents(ctx, info->u.hvm.smbios_firmware, + &data, &datalen); + if (e) { + LOGEV(ERROR, e, "failed to read SMBIOS firmware file %s", + info->u.hvm.smbios_firmware); + goto out; + } + libxl__ptr_add(gc, data); + if (datalen) { + /* Only accept non-empty files */ + args->smbios_module.data = data; + args->smbios_module.length = (uint32_t)datalen; + } + } + + if (info->u.hvm.acpi_firmware) { + data = NULL; + e = libxl_read_file_contents(ctx, info->u.hvm.acpi_firmware, + &data, &datalen); + if (e) { + LOGEV(ERROR, e, "failed to read ACPI firmware file %s", + info->u.hvm.acpi_firmware); + goto out; + } + libxl__ptr_add(gc, data); + if (datalen) { + /* Only accept non-empty files */ + args->acpi_module.data = data; + args->acpi_module.length = (uint32_t)datalen; + } + } + + return 0; +out: + return rc; } int libxl__build_hvm(libxl__gc *gc, uint32_t domid, @@ -544,10 +634,6 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid, libxl_ctx *ctx = libxl__gc_owner(gc); struct xc_hvm_build_args args = {}; int ret, rc = ERROR_FAIL; - const char *firmware = libxl__domain_firmware(gc, info); - - if (!firmware) - goto out; memset(&args, 0, sizeof(struct xc_hvm_build_args)); /* The params from the configuration file are in Mb, which are then @@ -557,22 +643,34 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid, */ args.mem_size = (uint64_t)(info->max_memkb - info->video_memkb) << 10; args.mem_target = (uint64_t)(info->target_memkb - info->video_memkb) << 10; - args.image_file_name = firmware; + + if (libxl__domain_firmware(gc, info, &args)) { + LOG(ERROR, "initializing domain firmware failed"); + goto out; + } ret = xc_hvm_build(ctx->xch, domid, &args); if (ret) { - LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm building failed"); + LOGEV(ERROR, ret, "hvm building failed"); goto out; } + ret = hvm_build_set_params(ctx->xch, domid, info, state->store_port, &state->store_mfn, state->console_port, &state->console_mfn, state->store_domid, state->console_domid); if (ret) { - LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm build set params failed"); + LOGEV(ERROR, ret, "hvm build set params failed"); goto out; } - rc = 0; + + ret = hvm_build_set_xs_values(gc, domid, &args); + if (ret) { + LOG(ERROR, "hvm build set xenstore values failed (ret=%d)", ret); + goto out; + } + + return 0; out: return rc; } @@ -634,7 +732,7 @@ int libxl__toolstack_restore(uint32_t domid, const uint8_t *buf, memcpy(&count, ptr, sizeof(count)); ptr += sizeof(count); - + if (size < sizeof(version) + sizeof(count) + count * (sizeof(struct libxl__physmap_info))) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "wrong size"); @@ -848,7 +946,7 @@ static void switch_logdirty_xswatch(libxl__egc *egc, libxl__ev_xswatch *watch, rc = libxl__xs_rm_checked(gc, t, lds->ret_path); if (rc) goto out; - rc = libxl__xs_transaction_commit(gc, &t); + rc = libxl__xs_transaction_commit(gc, &t); if (!rc) break; if (rc<0) goto out; } @@ -1320,7 +1418,7 @@ void libxl__xc_domain_save_done(libxl__egc *egc, void *dss_void, if (type == LIBXL_DOMAIN_TYPE_HVM) { rc = libxl__domain_suspend_device_model(gc, dss); if (rc) goto out; - + libxl__domain_save_device_model(egc, dss, domain_suspend_done); return; } diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index acc4bc9d9c..89a80300fe 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -308,6 +308,8 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("vpt_align", libxl_defbool), ("timer_mode", libxl_timer_mode), ("nested_hvm", libxl_defbool), + ("smbios_firmware", string), + ("acpi_firmware", string), ("nographic", libxl_defbool), ("vga", libxl_vga_interface_info), ("vnc", libxl_vnc_info), diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index bdd1865bf6..9c554ba040 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -882,6 +882,11 @@ static void parse_config_data(const char *config_source, } xlu_cfg_get_defbool(config, "nestedhvm", &b_info->u.hvm.nested_hvm, 0); + + xlu_cfg_replace_string(config, "smbios_firmware", + &b_info->u.hvm.smbios_firmware, 0); + xlu_cfg_replace_string(config, "acpi_firmware", + &b_info->u.hvm.acpi_firmware, 0); break; case LIBXL_DOMAIN_TYPE_PV: {